package com

import (
	"fmt"
	"gim-server/errs"
	"gim-server/utils"
	"github.com/gin-gonic/gin"
	jsoniter "github.com/json-iterator/go"
	"github.com/kayon/iploc"
	"io/ioutil"
	"net/http"
	"strings"
	"sync"
)

var (
	loc  *iploc.Locator
	once sync.Once
)

func getLoc() *iploc.Locator {
	once.Do(func() {
		var err error
		loc, err = iploc.Open("./qqwry.dat")
		if err != nil {
			panic(err)
		}
	})
	return loc
}

type IpGeoArgs struct {
	IP string `json:"ip" binding:"required"`
}

type IpGeoDto struct {
	Country  string `json:"country,omitempty"`
	Province string `json:"province,omitempty"`
	City     string `json:"city,omitempty"`
	Area     string `json:"area,omitempty"`
}

func ipgeo(ctx *gin.Context) {
	var (
		err  error
		args = new(IpGeoArgs)
	)
	if err = ctx.ShouldBindJSON(args); err != nil {
		utils.ERR(ctx, &utils.ErrArgs{
			Code: errs.ApiParamsErr,
			Err:  err,
		})
		return
	}

	dto := new(IpGeoDto)
	if strings.Contains(args.IP, ":") {
		//ipV6
		response, err := http.Get(fmt.Sprintf("https://ip.zxinc.org/api.php?type=json&ip=%s", args.IP))
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, new(struct{}))
			return
		}
		defer response.Body.Close()
		bytes, err := ioutil.ReadAll(response.Body)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, new(struct{}))
			return
		}
		result := new(struct {
			Code int `json:"code"`
			Data struct {
				Myip     string `json:"myip"`
				Location string `json:"location"`
				Country  string `json:"country"`
			} `json:"data"`
		})
		err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(bytes, result)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, new(struct{}))
			return
		}
		fmt.Printf("%+v\n", result)
		arr := strings.Split(result.Data.Country, "\t")
		for i, v := range arr {
			if i == 0 {
				dto.Country = v
			} else if i == 1 {
				dto.Province = v
			} else if i == 2 {
				dto.City = v
			} else {
				dto.Area = v
			}
		}
	} else {
		//ipV4
		detail := getLoc().Find(args.IP)
		dto.Country = detail.Country
		dto.Province = detail.Province
		dto.City = detail.City
		dto.Area = detail.County
	}
	utils.SUC(ctx, dto)
}
